#pragma once

#include "msgObj.hpp"
#include <atomic>

namespace Protocol {
class DevListAckMsgObject : public MsgObject {
private:
    static inline std::atomic<bool> _isGetList{false};

public:
    static bool isGetListAck(void) { return _isGetList.load(); }

private:
    std::size_t tick;
    std::size_t time;
    std::string src;
    struct Ack {
        std::size_t tick;
        std::size_t time;

        friend void from_json(const nlohmann::json &j, Ack &a) {
            if (j.contains("tick")) {
                j.at("tick").get_to(a.tick);
            }

            if (j.contains("time")) {
                j.at("time").get_to(a.time);
            }
        }
    } ack;
    struct List {
        std::size_t offset;
        std::size_t count;

        friend void from_json(const nlohmann::json &j, List &l) {
            if (j.contains("offset")) {
                j.at("offset").get_to(l.offset);
            }

            if (j.contains("count")) {
                j.at("count").get_to(l.count);
            }
        }
    } list;

    // struct Dev : public Device {
    // };
    using Dev = Device;

    std::vector<Dev> dev;

public:
    DevListAckMsgObject(std::shared_ptr<MqttClient> m, std::shared_ptr<DeviceManager> d)
        : MsgObject(m, d) {}

    friend void from_json(const nlohmann::json &j, DevListAckMsgObject &d) {
        if (j.contains("tick")) {
            j.at("tick").get_to(d.tick);
        }

        if (j.contains("time")) {
            j.at("time").get_to(d.time);
        }

        if (j.contains("src")) {
            j.at("src").get_to(d.src);
        }

        if (j.contains("ack")) {
            j.at("ack").get_to(d.ack);
        }

        if (j.contains("list")) {
            j.at("list").get_to(d.list);
        }

        if (j.contains("dev") && j.at("dev").is_array()) {
            for (const auto &dev : j.at("dev")) {
                d.dev.emplace_back(dev);
            }
        }
    }

    virtual bool parse(const std::string &topic, const std::string &payload) override {
        auto dest = subTopic(topic, 4);
        if (dest != selfSrc) {
            return false;
        }

        if (!nlohmann::json::accept(payload)) {
            return false;
        }

        nlohmann::json::parse(payload).get_to(*this);
        return true;
    }

    virtual MsgObject &action(void) override {
        _device->delAllDevice();

        for (const auto &d : dev) {
            _device->addDevice(d);
        }

        _isGetList = true;

        return *this;
    }

    virtual bool reply(void) override { return true; }
};

};  // namespace Protocol
